package com.hundsun.cprs.yyt.service.goods.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import com.hundsun.cprs.yyt.common.base.BaseService;
import com.hundsun.cprs.yyt.common.enums.EnumAreaCode;
import com.hundsun.cprs.yyt.common.exception.ServiceException;
import com.hundsun.cprs.yyt.service.goods.dao.GoodsDao;
import com.hundsun.cprs.yyt.service.goods.dao.GoodsWithAreaDao;
import com.hundsun.cprs.yyt.service.goods.domain.GoodsSpecs;
import com.hundsun.cprs.yyt.service.goods.domain.GoodsStockLog;
import com.hundsun.cprs.yyt.service.goods.domain.GoodsWithArea;
import com.hundsun.cprs.yyt.service.goods.domain.GoodsWithPlate;
import com.hundsun.cprs.yyt.service.goods.dto.GoodsAreaInfo;
import com.hundsun.cprs.yyt.service.goods.dto.GoodsInfo;
import com.hundsun.cprs.yyt.service.goods.dto.GoodsPublishInfo;
import com.hundsun.cprs.yyt.service.goods.enums.EnumGoodsStatus;
import com.hundsun.cprs.yyt.service.goods.enums.EnumHotGoodsType;
import com.hundsun.cprs.yyt.service.goods.enums.EnumStockType;
import com.hundsun.cprs.yyt.service.goods.service.GoodsAreaSerivce;
import com.hundsun.cprs.yyt.service.goods.service.GoodsService;
import com.hundsun.cprs.yyt.service.goods.service.GoodsSkuService;
import com.hundsun.cprs.yyt.service.goods.service.GoodsStockLogService;
import com.hundsun.cprs.yyt.service.goods.service.GoodsWithPlateService;
import com.hundsun.cprs.yyt.service.plate.domain.Plate;
import com.hundsun.cprs.yyt.service.plate.service.PlateService;
import com.hundsun.cprs.yyt.service.system.enums.EnumBussinessParam;
import com.hundsun.cprs.yyt.service.system.service.BusinessParamHelper;
import com.hundsun.cprs.yyt.service.system.service.BussinessParamService;

@Service
public class GoodsAreaServiceImpl extends BaseService implements GoodsAreaSerivce {
    
    @Autowired
    private GoodsWithAreaDao goodsWithAreaDao;
    @Autowired
    private GoodsWithPlateService goodsWithPlateService;
    @Autowired
    private GoodsDao goodsDao;
    @Autowired
    private BussinessParamService bussinessParamService;
    @Autowired
    private GoodsSkuService goodsSkuService;
    @Autowired
    private PlateService plateService;
    @Autowired
    private GoodsStockLogService goodsStockLogService;
    
    @Override
    public GoodsAreaInfo selectByAreaCodeAndGoodsId(String areaCode, Integer goodsId) {
        GoodsAreaInfo goodsAreaInfo = goodsWithAreaDao.selectByAreaCodeAndGoodsId(areaCode, goodsId);
        //加载绑定专场信息
        GoodsWithPlate goodsWithPlate = new GoodsWithPlate();
        goodsWithPlate.setGoodsId(goodsId.intValue());
        goodsWithPlate.setAreaCode(areaCode);
        List<GoodsWithPlate> goodsWithPlateList = goodsWithPlateService.selectGoodsWithPlate(goodsWithPlate);
        goodsAreaInfo.setPlateList(goodsWithPlateList);
        //加载SKU
        return goodsAreaInfo;
    }
    
    @Override
    public GoodsAreaInfo seLectById(Integer id) {
        GoodsAreaInfo goodsAreaInfo = goodsWithAreaDao.selectByPrimaryKey(id);
        //加载绑定专场信息
        GoodsWithPlate goodsWithPlate = new GoodsWithPlate();
        goodsWithPlate.setGoodsId(goodsAreaInfo.getGoodsId());
        goodsWithPlate.setAreaCode(goodsAreaInfo.getAreaCode());
        List<GoodsWithPlate> goodsWithPlateList = goodsWithPlateService.selectGoodsWithPlate(goodsWithPlate);
        goodsAreaInfo.setPlateList(goodsWithPlateList);
        //加载SKU
        
        return goodsAreaInfo;
    }

    @Override
    @Caching(
            evict = {
                    @CacheEvict(value="YYT:AREA:GOODS",key="'WHOLESALE_AREA:' + new String(#goodsAreaInfo.goods.id)"),
                    @CacheEvict(value="YYT:AREA:GOODS",key="'RETAIL_AREA:' + new String(#goodsAreaInfo.goods.id)"),
            }
    )
    @Transactional
    public void putOnGoods(GoodsAreaInfo goodsAreaInfo) {
        Assert.notNull(goodsAreaInfo, "参数必填");
        Assert.notNull(goodsAreaInfo.getGoods(), "商品必填");
        Assert.notNull(goodsAreaInfo.getGoods().getId(), "商品必填");
        Assert.hasLength(goodsAreaInfo.getAreaCode(),"上架专区必填");
        
        GoodsInfo goods = goodsAreaInfo.getGoods();
        //新增专区商品
        goodsAreaInfo.setGoodsId(goods.getId());
        goodsAreaInfo.setGoodsStatus(EnumGoodsStatus.PUBLISHED.getCode());
        goodsAreaInfo.setPublishTime(new Date());
        if (goodsAreaInfo.getTopShow() == null) {
        	goodsAreaInfo.setTopShow(Integer.valueOf(EnumHotGoodsType.NOT_HOT_GOODS.getCode()));
        }
        
        try {
            goodsWithAreaDao.insert(goodsAreaInfo);
        } catch (DuplicateKeyException e) {
            throw new ServiceException("专区商品已存在",e);
        }
        
        if (EnumAreaCode.RETAIL_AREA.getCode().equals(goodsAreaInfo.getAreaCode())) {
        	//零售区初始化默认SKU及专区商品基本属性
            if (goods.getQuotaRewardRate() == null) {
                goods.setQuotaRewardRate(BusinessParamHelper.getDoubleValue(bussinessParamService, EnumBussinessParam.DEFAULT_QUOTA_REWARD_RATE));
            }
            if (goods.getIntegralRewardRate() == null) {
                goods.setIntegralRewardRate(BusinessParamHelper.getDoubleValue(bussinessParamService, EnumBussinessParam.DEFAULT_INTEGRAL_REWARD_RATE));
            }
            goodsDao.updateByPrimaryKeySelective(goods);
            
            GoodsSpecs defaultSku = new GoodsSpecs();
            defaultSku.setAreaCode(goodsAreaInfo.getAreaCode());
            defaultSku.setGoodsPrice(goods.getCostPrice());
            defaultSku.setGoodsId(goods.getId());
            goodsSkuService.insert(defaultSku);
        } else {
        	goodsDao.updateByPrimaryKeySelective(goods);
        	
        	if (goodsAreaInfo.getSkus() != null) {
        		//补充专区商品信息
				for (GoodsSpecs sku : goodsAreaInfo.getSkus()) {
					sku.setGoodsId(goods.getId());
					sku.setAreaCode(goodsAreaInfo.getAreaCode());
				}
			}
        	goodsSkuService.insertList(goodsAreaInfo.getSkus());
        }
    }

    @Override
    @Caching(
            evict = {
                    @CacheEvict(value="YYT:AREA:GOODS",key="'WHOLESALE_AREA:' + new String(#goodsAreaInfo.goodsId)"),
                    @CacheEvict(value="YYT:AREA:GOODS",key="'RETAIL_AREA:' + new String(#goodsAreaInfo.goodsId)"),
            }
    )
    @Transactional
    public void updateGoodsAreaInfo(GoodsAreaInfo goodsAreaInfo) {
        GoodsAreaInfo dbRecord = seLectById(goodsAreaInfo.getId());
        if (dbRecord == null) {
            throw new ServiceException("专区商品不存在");
        }
        List<GoodsWithPlate> dbGoodsPlate = dbRecord.getPlateList();
        List<GoodsWithPlate> newGoodsPlate = new ArrayList<GoodsWithPlate>();
        //更新专场商品基本信息
        //更新SKU信息
        //更新专场数据
        goodsWithPlateService.deleteByAreaCodeAndGoodsId(goodsAreaInfo.getAreaCode(), goodsAreaInfo.getGoodsId());
        if (CollectionUtils.isNotEmpty(goodsAreaInfo.getPlateList())) {
            for(GoodsWithPlate item : goodsAreaInfo.getPlateList()){
                item.setId(null);
                item.setGoodsId(goodsAreaInfo.getGoodsId());
                item.setAreaCode(goodsAreaInfo.getAreaCode());
                goodsWithPlateService.insert(item);
                newGoodsPlate.add(item);
            }
        }
        
        //处理新人专场SKU及其优先量变更
        handleRetailAreaSku(dbRecord,dbGoodsPlate,newGoodsPlate);
    }
    
    protected void handleRetailAreaSku(GoodsAreaInfo dbRecord,List<GoodsWithPlate> dbGoodsPlateList,List<GoodsWithPlate> newGoodsPlateList){
        if (!EnumAreaCode.RETAIL_AREA.getCode().equals(dbRecord.getAreaCode())) {
            return;
        }
        //获取新人专场
        Plate newPlate = plateService.getNewPlate();
        if (newPlate == null) {
            return;
        }
        
        //获取老的新人专场设置信息
        GoodsWithPlate dbGoodsPlate = null;
        if (dbGoodsPlateList != null) {
            for(GoodsWithPlate item : dbGoodsPlateList){
                if (Long.compare(newPlate.getId(), item.getPlateId()) == 0) {
                    dbGoodsPlate = item;
                    break;
                }
            }
        }
        
        //获取新的新人专场设置信息
        GoodsWithPlate newGoodsPlate = null;
        for(GoodsWithPlate item : newGoodsPlateList){
            if (Long.compare(newPlate.getId(), item.getPlateId()) == 0) {
                newGoodsPlate = item;
                break;
            }
        }
        
        if (dbGoodsPlate == null && newGoodsPlate != null) {
            //创建
            GoodsSpecs newSku = goodsSkuService.selectDistinctSku(dbRecord.getAreaCode(),dbRecord.getGoodsId(),newPlate.getPlateCode());
            GoodsSpecs parentSku = null;
            if (newSku == null) {
                parentSku = goodsSkuService.selectDistinctSku(dbRecord.getAreaCode(),dbRecord.getGoodsId(),BigDecimal.ZERO.toString());
                newSku = new GoodsSpecs();
                newSku.setParent(parentSku);
                newSku.setGoodsId(parentSku.getGoodsId());
                newSku.setAreaCode(parentSku.getAreaCode());
                newSku.setPlateCode(newPlate.getPlateCode());
                newSku.setGoodsPrice(parentSku.getGoodsPrice());
                goodsSkuService.insert(newSku);
            } else {
                parentSku = newSku.getParent();
            }
            parentSku.setFrozenStock(newGoodsPlate.getGoodsStockDaily().intValue());
            goodsSkuService.updateFrozenStock(parentSku);
        } else if(dbGoodsPlate != null && newGoodsPlate != null) {
            //变更
            if (Long.compare(dbGoodsPlate.getGoodsStockDaily(), newGoodsPlate.getGoodsStockDaily()) != 0) {
                GoodsSpecs newSku = goodsSkuService.selectDistinctSku(dbRecord.getAreaCode(),dbRecord.getGoodsId(),newPlate.getPlateCode());
                if (newSku != null) {
                    GoodsSpecs parentSku = newSku.getParent();
                    parentSku.setFrozenStock(newGoodsPlate.getGoodsStockDaily().intValue());
                    goodsSkuService.updateFrozenStock(parentSku);
                }
            }
        } else if(dbGoodsPlate != null && newGoodsPlate == null) {
            //移除
            GoodsSpecs newSku = goodsSkuService.selectDistinctSku(dbRecord.getAreaCode(),dbRecord.getGoodsId(),newPlate.getPlateCode());
            if (newSku != null) {
                GoodsSpecs parentSku = newSku.getParent();
                parentSku.setFrozenStock(0);
                goodsSkuService.updateFrozenStock(parentSku);
            }
        } else {
            //忽略
        }
    }

	@Override
    @Caching(
            evict = {
                    @CacheEvict(value="YYT:AREA:GOODS",key="'WHOLESALE_AREA:' + new String(#goodsAreaInfo.goods.id)"),
                    @CacheEvict(value="YYT:AREA:GOODS",key="'RETAIL_AREA:' + new String(#goodsAreaInfo.goods.id)"),
            }
    )
	@Transactional
	public void updateBasicGoodsAreaInfo(GoodsAreaInfo goodsAreaInfo) {
		Assert.notNull(goodsAreaInfo,"参数必填");
		Assert.notNull(goodsAreaInfo.getGoods(),"商品基本信息必填");
		Assert.notNull(goodsAreaInfo.getGoods().getId(),"商品基本信息必填");
		Assert.hasLength(goodsAreaInfo.getAreaCode(),"专区必填");
		
		goodsDao.updateByPrimaryKeySelective(goodsAreaInfo.getGoods());
		
		//处理批发区专区SKU,零售区SKU系统维护则不需要处理
		if (EnumAreaCode.WHOLESALE_AREA.getCode().equals(goodsAreaInfo.getAreaCode())) {
			updateGoodsSpecs(goodsAreaInfo,goodsAreaInfo.getSkus());
		}
	}
	
	private void updateGoodsSpecs(GoodsAreaInfo goodsAreaInfo,List<GoodsSpecs> goodsSpecsList){
        //先获取历史规格列表
        List<GoodsSpecs> skuList = goodsSkuService.selectGoodsSpecsList(goodsAreaInfo.getGoodsId(),goodsAreaInfo.getAreaCode());
        Map<Long,GoodsSpecs> skuMap = com.hundsun.cprs.yyt.util.BeanUtils.mapByKey("id", skuList);
        if (goodsSpecsList != null) {
        	for (GoodsSpecs goodsSpecs:goodsSpecsList){
                if (goodsSpecs.getId() != null && goodsSpecs.getId() > 0) {
                    GoodsSpecs dbSku = skuMap.remove(goodsSpecs.getId());
                    //计算变化后的商品库存 = 可售库存+预占库存
                    Integer changedGoodsStock = goodsSpecs.getGoodsStock() + dbSku.getAllocatedStock();
                    //计算变化量
                    Integer changeAmount =  changedGoodsStock - dbSku.getGoodsStock();
                    dbSku.setGoodsStock(changedGoodsStock);
                    dbSku.setGoodsPrice(goodsSpecs.getGoodsPrice());
                    dbSku.setQuotaAmount(goodsSpecs.getQuotaAmount());
                    dbSku.setGoodsSpecs(goodsSpecs.getGoodsSpecs());
                    
                    goodsSkuService.updateSkuRecord(dbSku);
                    //记录库存变更流水
                    createStockLog(dbSku,changeAmount);
                } else {
                    goodsSpecs.setGoodsId(goodsAreaInfo.getGoodsId());
                    goodsSpecs.setAreaCode(goodsAreaInfo.getAreaCode());
                    goodsSpecs.setPlateCode(BigDecimal.ZERO.toString());
                    
                    goodsSkuService.insert(goodsSpecs);
                    //记录库存变更流水
                    createStockLog(goodsSpecs,goodsSpecs.getGoodsStock());
                }
            }
		}
        //删除规格
        for (GoodsSpecs sku : skuMap.values()){
            goodsSkuService.delete(sku.getId());
        }
    }
	
    /**
          * 库存流水记录生成
     *
     * */
    private void createStockLog(GoodsSpecs sku,Integer changeAmount){
        if (Math.abs(changeAmount) == 0) {
            return;
        }
        GoodsStockLog goodsStockLog = new GoodsStockLog();
        goodsStockLog.setSkuId(sku.getId());
        goodsStockLog.setCurrentStock(sku.getGoodsStock());
        goodsStockLog.setAreaCode(sku.getAreaCode());
        if (changeAmount > 0) {
            goodsStockLog.setInquantity(Math.abs(changeAmount));
            goodsStockLog.setOutquantity(0);
            goodsStockLog.setType(EnumStockType.IN_TYPE.getCode());
        } else {
            goodsStockLog.setInquantity(0);
            goodsStockLog.setOutquantity(Math.abs(changeAmount));
            goodsStockLog.setType(EnumStockType.OUT_TYPE.getCode());
            goodsStockLog.setAreaCode(sku.getAreaCode());
        }
        goodsStockLogService.createStockLog(goodsStockLog);
    }

}
